#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <utility>
#include <ctime>
#include <cassert>

#define Make_Rand() srand(((unsigned long)time(nullptr))^getpid()^0x327986^rand()%1234);



#define MAX_PROCESSES 5

///////////////////子进程的任务///////////////
typedef void(*func_t)();

void downLoadTask()
{
    std::cout <<'\n' <<": 下载任务" << std::endl;
    sleep(1);
}

void ioTask()
{
    std::cout <<'\n' << ": io任务" << std::endl;
    sleep(1);
}

void flashTask()
{
    std::cout <<'\n' << ": 刷新任务" << std::endl;
    sleep(1);
}

void loadTaskFunc(std::vector<func_t>* out)
{
    assert(out != nullptr);
    out->push_back(downLoadTask);
    out->push_back(ioTask);
    out->push_back(flashTask);
}

//////////////////////多进程///////////////////
class subEp // Endpoint
{
public:
    subEp(pid_t subId, int writefd)
    :subId_(subId), writefd_(writefd)
    {
        char nameBuffer[1024];
        snprintf(nameBuffer,sizeof(nameBuffer),"proccess-%d[pid(%d)-fd(%d)]",num++,subId_,writefd_);
        name_ = nameBuffer;
    }
public:
    static int num;
    std::string name_;
    pid_t subId_;
    int writefd_;

};

int subEp::num = 0;

int recvTask(int readFd)
{
    int code = 0;
    ssize_t s = read(readFd, &code, sizeof(code));
    if(s == 4) return code;
    else if(s <= 0) return -1;
    else return -1;
}

void sendTask(const subEp& process, int tasknum)
{
    std::cout<<'\n'<<"send task num:"<<tasknum<<" to "<<process.name_<<std::endl;
    int n = write(process.writefd_, &tasknum, sizeof(tasknum));
    //检查写入是否成功
    assert(n == sizeof(tasknum));
}

void createsubprocess(std::vector<subEp>* subs,std::vector<func_t>& funcMap)
{
    std::vector<int> deleteFd;
    for(int i=0;i<MAX_PROCESSES;i++)
    {

        int fds[2];
        int n = pipe(fds);
        //检查管道是否创建成功
        assert(n == 0);
        (void)n;
        //bug??
        pid_t id = fork();
        if(id==0)
        {
            int deleteFdNum = deleteFd.size();
            for(int i=0;i<deleteFdNum;++i) close(deleteFd[i]);
            //子进程
            close(fds[1]); // 关闭子进程的写端
            //获取命令码,否则阻塞
            while(true)
            {
                int commandCode = recvTask(fds[0]);
                if(commandCode >= 0 && commandCode < funcMap.size())
                {
                    funcMap[commandCode]();//执行并完成任务
                }
                else if(commandCode == -1) break;
            }

            exit(0);
        }
        close(fds[0]); // 关闭父进程的读端
        subEp sub(id, fds[1]);
        subs->push_back(std::move(sub));
        deleteFd.push_back(fds[1]);
    }
}

void loadBlanceContrl(std::vector<func_t>& funcMap,std::vector<subEp>& subs,int count)
{
    int processnum = subs.size();
    int tasknum = funcMap.size();
    bool quit = false;
    while(!quit)
    {
        //1.先选择一个子进程-->随机选一个子进程下标
        int idx = rand() % processnum;
        //2.再选择一个任务-->随机选一个任务下标
        int taskidx = rand() % tasknum;
        //3.发送任务给进程
        sendTask(subs[idx],taskidx);
        
        (--count == 0) ? quit = true : false;
        sleep(1);
    }
    //走到这里需要关闭父进程的写端,子进程读到0自动退出,关闭读端
    for(int i=0;i<processnum;++i) close(subs[i].writefd_);
}

void waitProcess(std::vector<subEp> process)
{
    int processnum = process.size();
    for(int i=0;i<processnum;++i)
    {
        waitpid(process[i].subId_, nullptr, 0);
        std::cout << "wait sub process success ..." << process[i].subId_ << std::endl;
    }
}

int main()
{
    //建立子进程,将子进程的ID和管道的写端保存在vector中
    std::vector<func_t> funcMap;
    loadTaskFunc(&funcMap);
    std::vector<subEp> subs;
    createsubprocess(&subs,funcMap);//子进程在函数中创建
    //在外面的就是父进程
    int taskCnt = 20;// 0: 一直进行
    loadBlanceContrl(funcMap,subs,taskCnt);
    //回收子进程
    waitProcess(subs);
    return 0;
}